/*
 *  Copyright (c) 2016, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the copyright holder nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @file
 * @brief
 *   This file includes the platform-specific initializers.
 */

#include "platform-posix.h"
#include "uart_send.h"

#if OPENTHREAD_POSIX_VIRTUAL_TIME == 0

#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef _WIN32
#include <libgen.h>
#include <syslog.h>
#include <getopt.h>
#include <string.h>
#include <errno.h>
#endif

#include <openthread/openthread.h>
#include <openthread/tasklet.h>
#include <openthread/platform/alarm-milli.h>

int SERIAL_FD = 0;
int DEBUG_FD= 0;

uint32_t NODE_ID = 0;
uint32_t WELLKNOWN_NODE_ID = 34;

#ifndef _WIN32
int     gArgumentsCount = 0;
char  **gArguments = NULL;
#endif

void usage(int argc, char *argv[])
{
    (void)argc;

    fprintf(stderr, "%s -f </dev/ttyUSBx> -n <node_id> -d <debug.fifo>\n", argv[0]);
    fprintf(stderr, "    The 'debug.fifo' needs to be created by f.e. mkfifo\n");
    fprintf(stderr, "    and can be read using 'cat debug.fifo -'\n");
}

void PlatformInit(int argc, char *argv[])
{
    /*if (argc != 3)
    {
        usage(argc, argv);
        exit(EXIT_FAILURE);
    }*/

#ifndef _WIN32
    openlog(basename(argv[0]), LOG_PID, LOG_USER);
    setlogmask(setlogmask(0) & LOG_UPTO(LOG_NOTICE));

    gArgumentsCount = argc;
    gArguments = argv;

    int err;
    char c;

    while ((c = getopt(argc, argv, "f:n:d:")) != -1) {
        switch (c) {
            case 'f' : {
                SERIAL_FD = open(optarg, O_RDWR, (S_IRUSR | S_IWUSR));
                err = errno;
                if (SERIAL_FD == -1) {
                    fprintf(stderr, "Err opening serial: %s\n", strerror(err));
                    exit(EXIT_FAILURE);
                }
                break;
            }
            case 'n' : {
                NODE_ID = (uint32_t)strtol(optarg, NULL, 0);
                break;
            }
            case 'd' : {
                DEBUG_FD = open(optarg, O_WRONLY, (S_IRUSR | S_IWUSR));
                err = errno;
                if (DEBUG_FD == -1) {
                    fprintf(stderr, "Err opening debug fifo: %s\n", strerror(err));
                    exit(EXIT_FAILURE);
                }
                break;
            }
            default : {
                usage(argc, argv);
                break;
            }
        }
    }
#endif
       //NODE_ID = (uint32_t)strtol(argv[1], &endptr, 0);
    if (NODE_ID < 1 || NODE_ID >= WELLKNOWN_NODE_ID)
    {
        usage(argc, argv);
        fprintf(stderr, "Invalid or no NODE_ID: %d\n", NODE_ID);
        exit(EXIT_FAILURE);
    }
    if (SERIAL_FD == 0) {
        usage(argc, argv);
        fprintf(stderr, "No serial device specified\n");
        exit(EXIT_FAILURE);
    }

    sendInit();
    platformAlarmInit();
    platformRadioInit();
    platformRandomInit();
}

void PlatformDeinit(void)
{
    platformRadioDeinit();
}

void PlatformProcessDrivers(otInstance *aInstance)
{
    fd_set read_fds;
    fd_set write_fds;
    fd_set error_fds;
    int max_fd = -1;
    struct timeval timeout;
    int rval;

    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);
    FD_ZERO(&error_fds);

    platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
    platformRadioUpdateFdSet(&read_fds, &write_fds, &max_fd);
    platformAlarmUpdateTimeout(&timeout);

    if (!otTaskletsArePending(aInstance))
    {
        rval = select(max_fd + 1, &read_fds, &write_fds, &error_fds, &timeout);

        if ((rval < 0) && (errno != EINTR))
        {
            perror("select");
            exit(EXIT_FAILURE);
        }
    }

    platformUartProcess();
    platformRadioProcess(aInstance);
    platformAlarmProcess(aInstance);
}

#endif // OPENTHREAD_POSIX_VIRTUAL_TIME == 0
